package com.tbit.utils;

import org.apache.log4j.Logger;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * @author ：hzw
 * @date ：Created in 2021/8/6 0:51
 * @description：
 * @modified By：
 * @version: $
 */
public class DateTimes {

    private final static Logger log = Logger.getLogger(DateTimeUtil.class);

    private static DateTimeFormatter YearMonthDay_ = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static DateTimeFormatter YearMonthDay = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static DateTimeFormatter YearMonth = DateTimeFormatter.ofPattern("yyyyMM");
    private static DateTimeFormatter YearMonthDay_Time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static DateTimeFormatter YearMonthDayTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private static DateTimeFormatter Hour = DateTimeFormatter.ofPattern("HH");
    private static DateTimeFormatter YearMonth_ = DateTimeFormatter.ofPattern("yyyy-MM");

    /**
     * 获取当前时间
     */
    public static String getNowTime() {
        return YearMonthDay_Time.format(LocalDateTime.now());
    }

    /**
     * 获取当前时间
     */
    public static String getNowTimeS1() {
        return YearMonthDayTime.format(LocalDateTime.now());
    }

    /**
     * 比较两个时间的大小
     */
    public static boolean compareTime(String oneTime, String twoTime) {
        return LocalDateTime.parse(oneTime, YearMonthDay_Time).isAfter(LocalDateTime.parse(twoTime, YearMonthDay_Time));
    }

    /**
     * 获取一段时间几分钟后的时间
     */
    public static String getTimeNestMin(String dateTime, Integer minute) {
        return YearMonthDay_Time.format(LocalDateTime.parse(dateTime, YearMonthDay_Time).minusMinutes(minute));
    }

    /**
     * 时间字符产转时间戳
     */
    public static long getTimestamp(String time) throws ParseException {
        return LocalDateTime.parse(time, YearMonthDay_Time).toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    /**
     * 获取下一分钟时间
     */
    public static String getNowTimeS1NextMin() {
        LocalDateTime localDateTime = LocalDateTime.now();
        return YearMonthDayTime.format(localDateTime.plusMinutes(1));
    }

    /**
     * 获取当前时间前后时间，参数分钟
     */
    public static String getNowTimeBefore(Integer minute) {
        return YearMonthDay_Time.format(LocalDateTime.now().plusMinutes(minute));
    }

    /**
     * 获取当前时间前后日期，参数天
     */
    public static String getNowDateTimeBefore(Integer day) {
        return YearMonthDay_.format(LocalDateTime.now().plusDays(day));
    }

    /**
     * 获取当前时间前后日期的结束时间，参数天
     */
    public static String getEndDateTimeBefore(Integer day) {
        LocalDate ld = LocalDate.now().plusDays(day);
        return YearMonthDay_Time.format(LocalDateTime.of(ld, LocalTime.MAX));
    }

    /**
     * 获取指定日期前后日期的结束时间，参数天
     */
    public static String getDateTimeBefore(String dateTime, Integer day) {
        return YearMonthDay_Time.format(LocalDateTime.of(LocalDate.from(LocalDateTime.parse(dateTime, YearMonthDay_Time).plusDays(day)), LocalTime.MAX));
    }

    /**
     * 获取当前时间
     */
    public static String getNowTimeyyyyMMdd() {
        LocalDate time = LocalDate.now();
        return YearMonthDay.format(time);
    }

    /**
     * 获取当前时间(yyyy-MM-dd)
     */
    public static String getNowTimeYMD() {
        LocalDate time = LocalDate.now();
        return YearMonthDay_.format(time);
    }

    /**
     * 获取yyyy-MM-dd HH:mm:dd指定时间年月 yyyy-MM-dd
     */
    public static String getYYMMDD_(String dateTime) {
        return YearMonthDay_.format(LocalDateTime.parse(dateTime, YearMonthDay_Time));
    }

    /**
     * 获取yyyy-MM-dd HH:mm:dd指定时间年月 yyyyMMdd
     */
    public static String getYYMMDD(String dateTime) {
        return YearMonthDay.format(LocalDateTime.parse(dateTime, YearMonthDay_Time));
    }

    /**
     * 获取两个时间差
     */
    public static int getTime(String time1, String time2) {
        LocalDateTime localDateTime1 = LocalDateTime.parse(time1, YearMonthDay_Time);
        LocalDateTime localDateTime2 = LocalDateTime.parse(time2, YearMonthDay_Time);
        return (int) ((localDateTime2.toInstant(ZoneOffset.of("+8")).toEpochMilli() - localDateTime1.toInstant(ZoneOffset.of("+8")).toEpochMilli()) / 1000);
    }

    /**
     * 字符串转日期 yyyy-MM-dd HH:mm:ss
     */
    public static Date StringToDateTime(String dateTime) {
        return Date.from(LocalDateTime.parse(dateTime, YearMonthDay_Time).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 字符串转日期 yyyy-MM-dd
     */
    public static Date StringToDate(String dateTime) {
        return Date.from(LocalDate.parse(dateTime, YearMonthDay_).atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 日期转字符串类型
     */
    public static String DateTimeToString(Date d) {
        return YearMonthDay_.format(d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
    }

    /**
     * 日期转字符串类型
     */
    public static String DateTimeTo(Date d) {
        return YearMonthDay.format(d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
    }

    /**
     * 日期转字符串类型
     */
    public static String DateToString(Date d) {
        return YearMonthDay_Time.format(d.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime());
    }

    /**
     * 日期转字符串类型
     */
    public static String DateString(Date d) {
        return YearMonth_.format(d.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime());
    }

    /**
     * 日期获取当天
     */
    public static int getDayOfMonth(Date date) {
        return date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime().getDayOfMonth();
    }

    /**
     * 获取月份的天数
     */
    public static int getDayNumOfMonth(Date date) {
        return date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime().getDayOfMonth();
    }

    /**
     * 时间转时间戳
     */
    public static long strTimestamp(String str) {
        long time;
        LocalDateTime localDateTime = LocalDateTime.parse(str, YearMonthDay_Time);
        time = localDateTime.toInstant(ZoneOffset.ofHours(12)).toEpochMilli();
        return time;
    }

    /**
     * 获取月份的第一天
     */
    public static String getMothStart() {
        return YearMonthDay_Time.format(LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth()));
    }

    /**
     * 获取月份的最后一天
     */
    public static String getMothEnd() {
        return YearMonthDay_Time.format(LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth()));
    }

    /**
     * 时间戳转时间
     */
    public static String timeToStr(long num) {
        String time = "";
        String pattern = "yyyy-MM-dd HH:mm:ss";
        LocalDateTime dateTime = LocalDateTime.ofEpochSecond(num / 1000L, 0, ZoneOffset.ofHours(12));
        time = dateTime.format(DateTimeFormatter.ofPattern(pattern));
        return time;
    }

    /**
     * 判断是否在指定时间一个小时前到达
     */
    @SuppressWarnings("deprecation")
    public static boolean inCheckPointTime(String dateTime, long time) {
        long oneHour = 1 * 3600 * 1000;
        Date d = Date.from(LocalDateTime.parse(dateTime, YearMonthDay_Time).toInstant(ZoneOffset.of("+8")));

        long checkTime = d.getHours() * 3600 * 1000 + d.getMinutes() * 60 * 1000 + d.getSeconds() * 1000;
        long timeRange = time - checkTime;
        if (timeRange >= 0 && timeRange <= oneHour) {
            return true;
        }
        return false;
    }

    /**
     * 指定日期加月份
     */
    public static Date addMonth(Date dateTime, int months) {
        Calendar calender = Calendar.getInstance();
        calender.setTime(dateTime);
        calender.add(Calendar.MONTH, months);
        return calender.getTime();
    }

    /**
     * 获取下一年的日期
     */
    public static String getNextYear() {
        return YearMonthDay_Time.format(LocalDateTime.now().plusYears(1));
    }

    /**
     * 获取下一年的日期，参考当前时间
     */
    public static String getNextYear(String baseTime) {
        return YearMonthDay_Time.format(LocalDateTime.parse(baseTime, YearMonthDay).plusYears(1));
    }

    /**
     * 获取两个时间的月份差
     */
    public static int getMonths(String startDay, String endDay) {
        Date startDate = StringToDateTime(startDay);
        Calendar startCalender = Calendar.getInstance();
        startCalender.setTime(startDate);
        int startMonths = startCalender.get(Calendar.YEAR) * 12 + startCalender.get(Calendar.MONTH) + 1;
        Date endDate = StringToDateTime(endDay);
        Calendar endCalender = Calendar.getInstance();
        endCalender.setTime(endDate);
        int endMonths = endCalender.get(Calendar.YEAR) * 12 + endCalender.get(Calendar.MONTH) + 1;
        return endMonths - startMonths;
    }

    /**
     * 获取一天前的日期
     */
    public static String getDayAgo() {
        return YearMonthDay_.format(LocalDate.now().plusDays(-1));
    }

    /**
     * 获取一周前的日期
     */
    public static String getAWeedAgo() {
        return YearMonthDay_.format(LocalDate.now().plusWeeks(-1));
    }

    /**
     * 获取一个月前的日期
     */
    @SuppressWarnings("static-access")
    public static String getAMonthAgo() {
        return YearMonthDay_Time.format(LocalDateTime.now().plusMonths(-1));
    }

    /**
     * 获取二个月前的日期
     */
    @SuppressWarnings("static-access")
    public static String get2MonthAgo() {
        return YearMonthDay_Time.format(LocalDateTime.now().plusMonths(-2));
    }

    /**
     * 获取和当前的小时差
     */
    public static Integer getHour(String startTime) {
        Integer day = LocalDateTime.now().getDayOfYear() - LocalDateTime.parse(startTime, YearMonthDay_Time).getDayOfYear();
        return LocalDateTime.now().getHour() - LocalDateTime.parse(startTime, YearMonthDay_Time).getHour() + day * 24;
    }

    /**
     * 获取和当前的小时差
     */
    public static String getSecondBefore(String dateTime, Integer seconds) {
        return YearMonthDay_Time.format(LocalDateTime.parse(dateTime, YearMonthDay_Time).plusHours(seconds));
    }

    /**
     * 获取两个时间小时差
     */
    public static Integer getHours(String startTime, String endTime) {
        Integer day = LocalDateTime.parse(endTime, YearMonthDay_Time).getDayOfYear() - LocalDateTime.parse(startTime, YearMonthDay_Time).getDayOfYear();
        return LocalDateTime.parse(endTime, YearMonthDay_Time).getHour() - LocalDateTime.parse(startTime, YearMonthDay_Time).getHour() + day * 24;
    }

    /**
     * 获取两个时间分钟差
     */
    public static Integer getMinutes(String startTime, String endTime) {
        Integer day = LocalDateTime.parse(endTime, YearMonthDay_Time).getDayOfYear() - LocalDateTime.parse(startTime, YearMonthDay_Time).getDayOfYear();
        Integer hour = LocalDateTime.parse(endTime, YearMonthDay_Time).getHour() - LocalDateTime.parse(startTime, YearMonthDay_Time).getHour();
        return LocalDateTime.parse(endTime, YearMonthDay_Time).getMinute() - LocalDateTime.parse(startTime, YearMonthDay_Time).getMinute() + hour * 60 + day * 24 * 60;
    }

    /**
     * 获取当前GMT时间
     */
    public static String getUTCNowTime(Long time) {
        TimeZone gmtTime = TimeZone.getTimeZone("GMT");
        Date date = new Date(time);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        format.setTimeZone(gmtTime);
        return format.format(date);
    }

    /**
     * 获取当前GMT时间
     */
    public static String getUTCNowTime() {
        TimeZone gmtTime = TimeZone.getTimeZone("GMT");
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        format.setTimeZone(gmtTime);
        return format.format(date);
    }

    /**
     * UTC0时间转换为客户本地时间
     */
    public static String converUtC0ToLoaclTime(String dateTime, Integer timeZoneSecond) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Long time = format.parse(dateTime).getTime() + timeZoneSecond * 1000;
            return format.format(new Date(time));
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
        }
        return dateTime;
    }

    /**
     * 根据时间区间求天数
     */
    public static int getDayCountByRange(String startDay, String endDay) {
        return LocalDate.parse(endDay, YearMonthDay_).getDayOfYear() - LocalDate.parse(startDay, YearMonthDay_).getDayOfYear();
    }

    /**
     * 获取两个日期之间的日期
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return 日期集合
     */
    public static List<String> getBetweenDates(String start, String end) {
        List<String> result = new ArrayList<String>();
        try {
            /**开始日期*/
            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(StringToDateTime(start));
            /**结束日期*/
            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(StringToDateTime(end));

            while (tempStart.before(tempEnd)) {
                result.add(DateToString(new Date(tempStart.getTimeInMillis())));
                tempStart.add(Calendar.DAY_OF_YEAR, 1);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }

    /**
     * 获取指定天前时间
     */
    public static String getDayAgoTime(Integer day) {
        return YearMonthDay_Time.format(LocalDateTime.now().minusDays(day));
    }

    /**
     * 获取指定小时前时间
     */
    public static String getHoursAgo(Integer hours) {
        return YearMonthDay_Time.format(LocalDateTime.now().minusHours(hours));
    }

    /**
     * 获取指定分钟前时间
     */
    public static String getMinsAgo(Integer mins) {
        return YearMonthDay_Time.format(LocalDateTime.now().minusMinutes(mins));
    }

    /***
     * 获取当前时间的小时
     * @return
     */
    public static Integer getNewHour() {
        return LocalDateTime.now().getHour();
    }

    /**
     * 判断是否小于今天
     *
     * @param date
     * @return
     */
    public static Boolean isBeforeToday(String date) {
        return LocalDate.parse(date, YearMonthDay_).isBefore(LocalDate.now());
    }

    /**
     * 判断是否大于今天
     *
     * @param date
     * @return
     */
    public static Boolean isAfterToday(String date) {
        return LocalDate.parse(date, YearMonthDay_).isAfter(LocalDate.now());
    }

    /**
     * 判断是否小于一个时间
     *
     * @param date
     * @return
     */
    public static Boolean isBeforeToday(String date, String dateTime) {
        return LocalDateTime.parse(date, YearMonthDay_Time).isBefore(LocalDateTime.parse(dateTime, YearMonthDay_Time));
    }

    /**
     * 判断是否大于一个时间
     *
     * @param date
     * @return
     */
    public static Boolean isAfterToday(String date, String dateTime) {
        return LocalDateTime.parse(date, YearMonthDay_Time).isAfter(LocalDateTime.parse(dateTime, YearMonthDay_Time));
    }

    //获取某段时间内的所有日期
    public static List<String> findDates(String dStart, String dEnd) {
        List<String> dateList = new LinkedList<>();
        try {
            Calendar cStart = Calendar.getInstance();
            cStart.setTime(Date.from(LocalDate.parse(dStart, YearMonthDay_Time).atStartOfDay(ZoneId.systemDefault()).toInstant()));
            dateList.add(YearMonthDay_.format(cStart.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()));
            while (LocalDate.parse(dEnd, YearMonthDay_Time).isAfter(cStart.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) {
                // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
                cStart.add(Calendar.DAY_OF_MONTH, 1);
                dateList.add(YearMonthDay_.format(cStart.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return dateList;
    }

    /**
     * 获取某段时间内的周一（二等等）的日期
     *
     * @param dataBegin 开始日期
     * @param dataEnd   结束日期
     * @param weekDays  获取周几，1－6代表周一到周六。0代表周日
     * @return 返回日期List
     */
    public static Map<String, String> getDayOfWeekWithinDateInterval(String dataBegin, String dataEnd, int weekDays) {

        List<String> dateResult = new ArrayList<>();
        Calendar cal = Calendar.getInstance();
        String[] dateInterval = {dataBegin, dataEnd};
        Date[] dates = new Date[dateInterval.length];
        for (int i = 0; i < dateInterval.length; i++) {
            String[] ymd = dateInterval[i].split("[^\\d]+");
            cal.set(Integer.parseInt(ymd[0]), Integer.parseInt(ymd[1]) - 1, Integer.parseInt(ymd[2]));
            dates[i] = cal.getTime();
        }
        Map<String, String> map = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String obj1, String obj2) {
                return obj1.compareTo(obj2);
            }
        });
        String DBegin = getYYMMDD(dataBegin);
        map.put(getStringWeekUtil(DBegin), DBegin);
        for (Date date = dates[0]; date.compareTo(dates[1]) <= 0; ) {
            cal.setTime(date);
            if (cal.get(Calendar.DAY_OF_WEEK) - 1 == weekDays) {
                String format = DateTimeTo(date);
                dateResult.add(format);
                map.put(getStringWeekUtil(format), format);
            }
            cal.add(Calendar.DATE, 1);
            date = cal.getTime();
        }
        return map;
    }

    /**
     * 返回一个时间的周数
     */
    public static String getStringWeek(String date) {
        String weeks = null;
        Date d = Date.from(LocalDate.parse(date, YearMonthDay_Time).atStartOfDay(ZoneId.systemDefault()).toInstant());
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.setFirstDayOfWeek(Calendar.MONDAY);  //设置一周的第一天是周一
        cal.get(Calendar.WEEK_OF_YEAR);

        int year = cal.get(Calendar.YEAR);
        int week = cal.get(Calendar.WEEK_OF_YEAR);

        cal.add(Calendar.DAY_OF_MONTH, -7);  //上一周

        //判断是否同一年，并且本周周数小于上周周数，则在上周周数的基础上加一
        if (year == cal.get(Calendar.YEAR) && week < cal.get(Calendar.WEEK_OF_YEAR)) {
            week = cal.get(Calendar.WEEK_OF_YEAR) + 1;
        }
        String stDateWe = year + "" + (week < 10 ? "0" + week : week);
        weeks = stDateWe;
        return weeks;
    }

    /**
     * 返回一个时间的周数
     */
    public static String getStringWeekUtil(String date) {
        String weeks = null;
        Date d = Date.from(LocalDate.parse(date, YearMonthDay).atStartOfDay(ZoneId.systemDefault()).toInstant());
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.setFirstDayOfWeek(Calendar.MONDAY);  //设置一周的第一天是周一
        cal.get(Calendar.WEEK_OF_YEAR);
        int year = cal.get(Calendar.YEAR);
        int week = cal.get(Calendar.WEEK_OF_YEAR);
        cal.add(Calendar.DAY_OF_MONTH, -7);  //上一周
        //判断是否同一年，并且本周周数小于上周周数，则在上周周数的基础上加一
        if (year == cal.get(Calendar.YEAR) && week < cal.get(Calendar.WEEK_OF_YEAR)) {
            week = cal.get(Calendar.WEEK_OF_YEAR) + 1;
        }
        String stDateWe = year + "" + (week < 10 ? "0" + week : week);
        weeks = stDateWe;
        return weeks;
    }

    /**
     * 返回一段时间内的，开始月，结束月的第一天
     *
     * @throws ParseException
     */
    public static List<String> getMonthDay(String date1, String date2) throws ParseException {
        Date parse = Date.from(LocalDateTime.parse(date1, YearMonthDay_Time).atZone(ZoneId.systemDefault()).toInstant());
        Date parse2 = Date.from(LocalDateTime.parse(date2, YearMonthDay_Time).atZone(ZoneId.systemDefault()).toInstant());
        Calendar c1 = Calendar.getInstance();
        c1.setTime(parse);
        int year = c1.get(Calendar.YEAR);//转为周一
        int month = c1.get(Calendar.MONTH);
        c1.set(year, month, 1, 0, 0, 0);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(parse2);
        int weekYear2 = c2.get(Calendar.YEAR);
        int weekOfYear2 = c2.get(Calendar.WEEK_OF_YEAR);
        c2.setWeekDate(weekYear2, weekOfYear2, Calendar.SUNDAY);
        List<String> list = new LinkedList<>();
        while (true) {
            list.add(DateString(c1.getTime()));
            c1.set(Calendar.MONTH, c1.get(Calendar.MONTH) + 1);//下一个月<结束日期
            if (c1.getTimeInMillis() >= c2.getTimeInMillis()) {
                break;
            }
        }
        return list;
    }

    /**
     * 获取时间范围内每个周一和周末
     * 第一天不一定是周一 、最后一天不一定是周日
     *
     * @param date1
     * @param date2
     * @return
     */
    public static Map<String, String> findDatesOfWeek(String date1, String date2) {
        Date dBegin = StringToDateTime(date1);
        Date dEnd = StringToDateTime(date2);

        Map<String, String> map = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String obj1, String obj2) {
                return obj1.compareTo(obj2);
            }
        });
        map.put(getStringWeek(DateToString(dBegin)), DateToString(dBegin));
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            //日期星期日提出来
            if (calBegin.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
                calBegin.add(Calendar.DAY_OF_MONTH, 1);
                Date endDate = calBegin.getTime();
                map.put(getStringWeek(DateToString(endDate)), DateToString(endDate));
                calBegin.add(Calendar.DAY_OF_MONTH, 6);
            } else {
                calBegin.add(Calendar.DAY_OF_MONTH, 1);
            }
        }
        return map;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(getNowTimeBefore(-10));
    }
}
